package com.cjyd.hrjb.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cjyd.hrjb.exception.ServiceException;
import com.cjyd.hrjb.mapper.AdminMapper;
import com.cjyd.hrjb.model.dto.AdminDto;
import com.cjyd.hrjb.model.entity.Admin;
import com.cjyd.hrjb.model.enums.AdminState;
import com.cjyd.hrjb.service.AdminService;
import com.cjyd.hrjb.service.VerifyCodeService;
import com.cjyd.hrjb.utils.CryptoUtil;
import com.cjyd.hrjb.utils.JwtUtil;
import com.cjyd.hrjb.utils.ResultCode;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;

/**
 * Created fei wo by 2020/4/6
 */
@Service
public class AdminServiceImpl implements AdminService {

    private static final String ADMIN_LOGIN_REDIS_KEY = "admin:login:%s";

    private final AdminMapper adminMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final CryptoUtil cryptoUtil;
    private final JwtUtil jwtUtil;
    private final VerifyCodeService verifyCodeService;

    public AdminServiceImpl(AdminMapper adminMapper, StringRedisTemplate stringRedisTemplate, CryptoUtil cryptoUtil, JwtUtil jwtUtil, VerifyCodeService verifyCodeService) {
        this.adminMapper = adminMapper;
        this.stringRedisTemplate = stringRedisTemplate;
        this.cryptoUtil = cryptoUtil;
        this.jwtUtil = jwtUtil;
        this.verifyCodeService = verifyCodeService;
    }

    @Override
    public Admin add(AdminDto adminDto) {
        LambdaQueryWrapper<Admin> eq = Wrappers.<Admin>lambdaQuery().eq(Admin::getEmail, adminDto.getEmail());
        Integer count = adminMapper.selectCount(eq);
        if (count > 0) throw new ServiceException(ResultCode.ADMIN_ALREADY_EXISTS);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminDto, admin);
        admin.setPasswordHash(cryptoUtil.cryptPassword(adminDto.getPassword()));
        admin.setState(AdminState.NORMAL);
        int insert = adminMapper.insert(admin);
        if (insert != 1) throw new ServiceException(ResultCode.ADD_ADMIN_FAIL);
        return admin;
    }

    @Override
    public Admin edit(AdminDto adminDto) {
        Admin admin = adminMapper.selectById(adminDto.getId());
        if (admin == null) throw new ServiceException(ResultCode.ADMIN_NOT_EXISTS);

        admin.setNickname(adminDto.getNickname());
        admin.setEmail(adminDto.getEmail());
        admin.setRole(adminDto.getRole());
        admin.setState(adminDto.getState());
        admin.setPasswordHash(adminDto.getPassword());

        int update = adminMapper.updateById(admin);
        if (update != 1) throw new ServiceException(ResultCode.UPDATE_ADMIN_FAIL);
        return admin;
    }

    @Override
    public void delete(Long adminId) {
        int delete = adminMapper.deleteById(adminId);
        if (delete != 1) throw new ServiceException(ResultCode.DEL_ADMIN_FAIL);
    }

    @Override
    public List<Admin> list() {
        return adminMapper.selectList(Wrappers.emptyWrapper());
    }

    @Override
    public Admin login(AdminDto adminDto) {
        // 验证验证码是否正确
        verifyCodeService.verifyCode(adminDto.getVerifyCode(), adminDto.getVerifyFlag());

        LambdaQueryWrapper<Admin> queryWrapper = Wrappers.<Admin>lambdaQuery()
                .eq(Admin::getEmail, adminDto.getEmail())
                .eq(Admin::getPasswordHash, cryptoUtil.cryptPassword(adminDto.getPassword()));
        Admin admin = adminMapper.selectOne(queryWrapper);
        if (admin == null) throw new ServiceException(ResultCode.LOGIN_ADMIN_FAIL);

        if (!AdminState.NORMAL.getValue().equals(admin.getState().getValue())) {
            throw new ServiceException(ResultCode.ADMIN_STATE_DISABLE);
        }

        // get token
        String token = jwtUtil.generateToken(admin.getId());
        admin.setToken(token);
        stringRedisTemplate.opsForValue().set(String.format(ADMIN_LOGIN_REDIS_KEY, token), JSONUtil.toJsonStr(admin), Duration.ofDays(7));

        return admin;
    }

    @Override
    public void logout(String token) {
        stringRedisTemplate.delete(String.format(ADMIN_LOGIN_REDIS_KEY, token));
    }
}
